/**
 * Desenvolvido pela Fábrica de Software do CESUPA.
 * Todos os direitos reservados.
 */
package br.cesupa.fabsoft.nomedoprojeto.system.infra.filters;

import br.cesupa.fabsoft.nomedoprojeto.system.application.facades.ApplicationFacade;
import br.cesupa.fabsoft.nomedoprojeto.system.infra.view.MessageType;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * At the first request of client, this filter will be fired and redirect the
 * user to the appropriate timeout page if the session is not valid.
 *
 * @author hturksoy
 */
public class SessionTimeoutFilter implements Filter {

    /**
     * The page to be displayed if the session expires.
     */
    private String timeoutPage;

    /**
     * Check for the <code>timeout-page</code> variable to initialize the filter.
     *
     * @param config
     * @throws ServletException
     * @see Filter#init(javax.servlet.FilterConfig)
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        timeoutPage = filterConfig.getInitParameter("timeout-page");
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain filterChain) throws IOException,
            ServletException {
        if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) {

            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            HttpSession httpSession = ((HttpServletRequest) request).getSession();

            // is session expire control required for this request?
            if (isSessionControlRequiredForThisResource(httpServletRequest)) {

                // is session invalid?
                if (isSessionInvalid(httpServletRequest)) {
                    String timeoutURL = httpServletRequest.getContextPath() + "/" + getTimeoutPage();
                    httpSession.setAttribute("applicationStatusMessage",
                            ApplicationFacade.getViewFacade().createMessage(
                    "SessionEnd", MessageType.WARNING));
                    httpServletResponse.sendRedirect(timeoutURL);
                    return;
                }
            }
        }
        filterChain.doFilter(request, response);
    }

    /*
     * Session shouldn’t be checked for some pages. For example: for timeout
     * page.. Since we’re redirecting to timeout page from this filter, if we
     * don’t disable session control for it, filter will again redirect to it
     * and this will be result with an infinite loop.
     */
    private boolean isSessionControlRequiredForThisResource(
            HttpServletRequest httpServletRequest) {
        boolean isControlRequired = true;

        String requestPath = httpServletRequest.getRequestURI();
        if (requestPath.equals(httpServletRequest.getContextPath() + "/")) {
            isControlRequired = false;
        } else {
            isControlRequired = !requestPath.contains(getTimeoutPage());
        }
        return isControlRequired;
    }

    /**
     * Checks if the session is invalid.
     *
     * @param httpServletRequest the last http request
     * @return true if the request session is invalid, false otherwise
     */
    private boolean isSessionInvalid(HttpServletRequest httpServletRequest) {
        return ((httpServletRequest.getRequestedSessionId() != null) &&
                !httpServletRequest.isRequestedSessionIdValid());
    }

    public void destroy() {
    }

    /**
     * 
     * @return the page showed when session expires
     */
    public String getTimeoutPage() {
        return timeoutPage;
    }

    /**
     * 
     * @param timeoutPage the target page to be showed when session expires
     */
    public void setTimeoutPage(String timeoutPage) {
        this.timeoutPage = timeoutPage;
    }
}

